package com.zrwl.poscloud.core.restapi.proxy;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zrwl.poscloud.commons.holder.RequestHolder;
import com.zrwl.poscloud.commons.holder.SpringContextHolder;
import com.zrwl.poscloud.xo.service.AdminService;
import com.zrwl.poscloud.xo.service.UserService;
import com.zrwl.poscloud.xo.vo.AdminVO;
import com.zrwl.poscloud.xo.vo.UserVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.core.MethodParameter;
import org.springframework.util.PathMatcher;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Objects;

@RestController
@RefreshScope
@RequestMapping("/proxy")
@Slf4j
public class ProxyRestApi {
    @Autowired
    private AdminService adminService;
    @Autowired
    private UserService userService;
    @Autowired
    private RequestMappingHandlerMapping handlerMapping;

    @RequestMapping(value = "/request")
    public String request(String meJsonStr, String requestUrl, String requestHeaderJsonStr, String requestParamJsonStr) {
        /***
         * 1 token拿出来
         * 2 用token去setMe
         * 3 解析url 和param 执行返回结果
         */
        JSONObject me = JSON.parseObject(meJsonStr);
        if(me.get("requestMode")!=null&& "system".equals(me.get("requestMode"))){//系统请求

        }else {
            JSONObject header = JSON.parseObject(requestHeaderJsonStr);
            String token = header.getString("token");
            HttpServletRequest request = RequestHolder.getRequest();
            request.setAttribute("cloudRequest", token);
            if(me.get("userEmployeeRVO") != null){
                UserVO meVO = JSON.toJavaObject(me, UserVO.class);
                UserVO userVO = userService.getMe();
                if(userVO == null || !Objects.equals(userVO.getUid(), meVO.getUid())){
                    userService.setMe(token, meVO);
                }
            }else {
                AdminVO meVO = JSON.toJavaObject(me, AdminVO.class);
                AdminVO adminVO = adminService.getMe();
                if(adminVO == null || !Objects.equals(adminVO.getUid(), meVO.getUid())){
                    adminService.setMe(token, meVO);
                }
            }
        }
        JSONObject param = JSON.parseObject(requestParamJsonStr);
        Method method = null;
        Object apiBean = null;
        MethodParameter[] methodParameters = null;
        Map<RequestMappingInfo, HandlerMethod> map = handlerMapping.getHandlerMethods();
        for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : map.entrySet()) {
            RequestMappingInfo mappingInfo = entry.getKey();
            HandlerMethod handlerMethod = entry.getValue();
            if (handlerMapping.getPathMatcher() != null) {
                PathMatcher pathMatcher = handlerMapping.getPathMatcher();
                for (String singlePath : mappingInfo.getPatternsCondition().getPatterns()) {
                    /**
                     * Find the closest match
                     */
                    if (pathMatcher.match(singlePath, requestUrl) || pathMatcher.matchStart(singlePath, requestUrl)) {
                        method = handlerMethod.getMethod();
                        apiBean = SpringContextHolder.getBean(handlerMethod.getBeanType());
                        methodParameters = handlerMethod.getMethodParameters();
//                        mappingInformationDTO=new MappingInformationDTO(handlerMethod.getBean(),handlerMethod.getMethod().getDeclaringClass(),
//                                handlerMethod.getMethod().getName(), mappingInfo.getPatternsCondition().getPatterns());
                    }
                }
            } else {
                if (mappingInfo.getPatternsCondition().getPatterns().contains(requestUrl)) {
                    method = handlerMethod.getMethod();
                    apiBean = SpringContextHolder.getBean(handlerMethod.getBeanType());
                    methodParameters = handlerMethod.getMethodParameters();
//                    mappingInformationDTO=new MappingInformationDTO(handlerMethod.getBean(),handlerMethod.getMethod().getDeclaringClass(),
//                            handlerMethod.getMethod().getName(), mappingInfo.getPatternsCondition().getPatterns());
                    break;
                }
            }
        }
        if (method != null) {
            try {
                //如果不是bean+bindingResult 或者只有bean的方法是无法准确传递参数顺序的，即便可以也比较麻烦，需要人工匹配invoke的参数顺序，暂时没有方案
                if (methodParameters.length == 2) {
                    Object paramVO = JSON.toJavaObject(param, methodParameters[0].getParameterType());
                    Object result=method.invoke(apiBean, paramVO, null);
                    return result.toString();
                } else if (methodParameters.length == 1) {
                    Object paramVO = JSON.toJavaObject(param, methodParameters[0].getParameterType());
                    return method.invoke(apiBean, paramVO).toString();
                } else if (methodParameters.length == 0) {

                    return method.invoke(apiBean).toString();

                } else {
                    throw new RuntimeException("api参数请使用bean传递否则无法识别");
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                throw new RuntimeException("IllegalAccessException", e);
            } catch (InvocationTargetException e) {
                e.printStackTrace();
                throw new RuntimeException("InvocationTargetException", e);
            }
        } else {
            throw new RuntimeException("找不到API" + requestUrl);
        }
//        Class<?> ApiType;
        //用注解查询（推荐使用）
//        ApiType = SpringContextHolder.getBean(mappingInformationDTO.beanName.getClass().getName());
//        //反射设置方法参数。
//        Method method = ApiType.getDeclaredMethod(requestMap[1], ProxyRequestVO.class);
//        //在ApplicationContext中根据class取出已实例化的bean
//        responseVO = (ProxyResponseVO) method.invoke(SpringContextHolder.getBean(ApiType), requestVO);
    }


}